package us.icitap.commandcenter.business.ejb;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import us.icitap.commandcenter.business.Result;
import us.icitap.commandcenter.business.ejb.dao.Expression;
import us.icitap.commandcenter.business.ejb.dao.QueryBuilder;
import us.icitap.commandcenter.business.ejb.persistence.AppLog;
import us.icitap.commandcenter.business.ejb.persistence.Call;
import us.icitap.commandcenter.business.ejb.persistence.CallStatusEnum;
import us.icitap.commandcenter.business.ejb.persistence.CommandCenter;
import us.icitap.commandcenter.business.ejb.persistence.Dispatcher;
import us.icitap.commandcenter.business.ejb.persistence.UniqueNumber;

@Stateless
public class PersistenceBean implements IPersistenceBean{

	@PersistenceContext(unitName="CommandCenter")
	EntityManager em;
	
	

	private <T> T saveEntityDB(T entity) {
		  return em.merge(entity);
		 
	}

	public <T> Result<T> saveEntity(T entity){
		try {
			T object =  this.saveEntityDB(entity);
			return new Result<T>(object, true, null);
		} catch (Exception e) {
			return new Result<T>(null, false, e.getMessage());
		}
	}
	
	public <T> Result<List<T>> getList(Class<T> entityClass, boolean withStatus, String orderBy){
		
		try {
			List<T> list = getListFromDB( entityClass,  withStatus,  orderBy);
			return new Result<List<T>>(list, true, null);
		} catch (Exception e) {
			e.printStackTrace();
			return new Result<List<T>>(null, false, e.getMessage());
		}
		
		
		
	}

	private void writeLog(String username, String log){
		try {
			AppLog appLog = new AppLog(log, new Date(), username);
			this.saveEntity(appLog);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Result<Call> createCall(Call call){
		Call c = null;
		try {
			call.setRecordDate(new Date());
			c = this.saveEntityDB(call);
			
			writeLog(call.getRecordUser(),  call.getRecordUser().toUpperCase() +" krijoi telefonaten me id: " + c.getId());
			return new Result<Call>(c, true, null);
		} catch (Exception e) {
			e.printStackTrace();
			return new Result<Call>(null, false, e.getMessage());
		}
	}
	

	private <T> List<T> getListFromDB(Class<T> entityClass, boolean withStatus, String orderBy) {
		
			String sql = "Select o from " + entityClass.getSimpleName() + " o";
			if (withStatus) {
				sql += " where o.status = :status order by o.tag DESC";
				return em.createQuery(sql).setParameter("status", true).getResultList();
			}

			if(orderBy != null)
				sql += " order by " + orderBy + " DESC";
			return em.createQuery(sql).getResultList();

		
	}
	


	@SuppressWarnings("unchecked")
	public <T> Result<List<T>> findByCriteria(List<Expression> expressions,
			String groupByFields, String sortFields, Class<T> entity) {

		try {
			Query query = QueryBuilder.createQuery(em, expressions,
					groupByFields, sortFields, entity.getSimpleName());
			List<T> listT = query.setMaxResults(500).getResultList();
			
			return new Result<List<T>>(listT, true, null);
		} catch (Exception e) {
			return new Result<List<T>>(null, false, e.getMessage());
		}
	}
	
	public  Result<List<CommandCenter>> getCommandCenters(){
		try {
			List<CommandCenter> ccs = em.createQuery("Select o from CommandCenter o where o.status = :status").setParameter("status", true).getResultList();
			return new Result<List<CommandCenter>>(ccs, true, null);
		} catch (Exception e) {
			return new Result<List<CommandCenter>>(null, false, e.getMessage());
		}
	}
	
	public Result<List<Dispatcher>> getDispatchers(CommandCenter cc){
		try {
			List<Dispatcher> dispatchers = em.createQuery("Select o from Dispatcher o where o.commandCenter = :cc AND o.status = :status").setParameter("cc", cc).setParameter("status", true).getResultList();
			return new Result<List<Dispatcher>>(dispatchers, true, null);
		} catch (Exception e) {
			return new Result<List<Dispatcher>>(null, false, e.getMessage());
			// TODO: handle exception
		}
	}
	
	public <T> Result<T> findEntityById(Object id, Class<T> entity) {
		try {

			String sql = "Select o from " + entity.getSimpleName()+ " o where o.id = :id ";
			T obj =  (T) em.createQuery(sql).setParameter("id", id).getSingleResult();

			return new Result<T>(obj, true, null);
		} catch (NoResultException e) {
			return new Result<T>(null, false, e.getMessage());

		} catch (Exception e) {
			return new Result<T>(null, false, e.getMessage());
		}

	}
	
	public Result<List<Call>> findCallByDispatcherAndStatus(Dispatcher dispatcher, Date date, CallStatusEnum callStatus){
		
		try {
			List<Call> calls = em.createQuery("Select o from Call o  where o.mainDispatcher = :dispatcher AND o.recordDate >= :date AND o.actualStatus = :status")
					.setParameter("dispatcher", dispatcher)
					.setParameter("date", date)
					.setParameter("status", callStatus).getResultList();
			return new Result<List<Call>>(calls, true, null);
		} catch (Exception e) {
			return new Result<List<Call>>(null, false, e.getMessage());
		}
	}
	

	public Result<List<Object[]>> findCallsTotalBasedOnStatus(CommandCenter commandCenter, Date minDate, Date maxDate){
		try {
			
			List<Object[]> rez;
			
			rez= em.createQuery("select o.actualStatus, COUNT(o) from Call o where o.commandCenter = :cc AND o.recordDate >= :minDate AND o.recordDate < :maxDate GROUP BY o.actualStatus")
					.setParameter("cc", commandCenter)
					.setParameter("minDate", minDate)
					.setParameter("maxDate", maxDate).getResultList();
					
			return new Result<List<Object[]>>(rez, true,null);
		} catch (Exception e) {
			System.out.println("AppEjb.findCallsTotalBasedOnStatus()");
			e.printStackTrace();
			return new Result<List<Object[]>>(null, false,null);
		}
	}
	
	public Result<Long> findUniqueNumberTotal(CommandCenter commandCenter, Date minDate, Date maxDate){
		try {
			Long total = (Long) em.createQuery("Select COUNT(o) from Call o where o.commandCenter = :cc AND o.recordDate >= :minDate AND o.recordDate < :maxDate AND o.uniqueNumber is not null ")
			.setParameter("cc", commandCenter)
			.setParameter("minDate", minDate)
			.setParameter("maxDate", maxDate).getSingleResult();
			
			return new Result<Long>(total, true, null);
		} catch (Exception e) {
			e.printStackTrace();
			return new Result<Long>(null, false, e.getMessage());
		}
	}

	@Override
	public Result<Call> generateUniqueNumber(Call call) {
		// Formati i numrit unik do te jete vvvv-mm-dd-xxxx
		// vvvv- viti, mm- muaji, dd-dita, xxxx - numer 4-shifror 0001-9999
		 
		try {
			Calendar c = Calendar.getInstance();
			
			
			call.getUniqueNumber().setRecordDate(c.getTime());
			
			String month = (new Integer(c.get(Calendar.MONTH) + 1)).toString();
			
			if(month.length()<2) month = "0" + month;
			
			String day = (new Integer(c.get(Calendar.DAY_OF_MONTH))).toString();
			
			if(day.length()<2) day = "0" + day;
			
			String date = c.get(Calendar.YEAR) + month + day;
			
			String sql = "select  MAX(SUBSTR(t.unique_number,9,4)) from mpc.unique_number  t where SUBSTR(t.unique_number,1,8) = '"+ date +"' ";
			
			Vector objects =  (Vector) em.createNativeQuery(sql).getResultList();
			 
			String max;
			Integer maxUN=0;
			
			if (objects == null || objects.isEmpty()) 
			{
				max= "0001";
				
			}
			else {
				if (objects.get(0) == null) max= "0001";
				else {
					maxUN = new Integer(objects.get(0).toString());
					maxUN  = maxUN + new Integer(1);
					if (maxUN > 999) {
						max=(new Integer(maxUN)).toString();
					}
					else if (maxUN >99 && maxUN <= 999) {
						max="0" + (new Integer(maxUN)).toString();
					}
					else if (maxUN >9 && maxUN <= 99) {
						max="00" + (new Integer(maxUN)).toString();
					}
					else {
						max="000" + (new Integer(maxUN)).toString();
					}
				}

			}
			
			call.getUniqueNumber().setUniqueNumber(date + max);
			
			Call saveCall = this.saveEntityDB(call);
			
			return new Result<Call>(saveCall, true, null);
		} catch (Exception e) {
			e.printStackTrace();
			return new Result<Call>(null, false, e.getMessage());
		}
		
	}
}
